using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Threading;
using MineFlagger;
using System.Diagnostics;
using System.Drawing.Imaging;


namespace MineFlagger {


	public class Form1 : System.Windows.Forms.Form {
        
        public static readonly string AppName = "MineFlagger";
        public static readonly string AppVersion = "v0.0.2";
        
        GameBoard gameBoard;
		public Random rnd;
        private GameBoardView gameBoardView1;

        IViewer view;


		#region WinVars

        private System.Windows.Forms.TextBox txtWidth;
		private System.Windows.Forms.TextBox txtHeight;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.TextBox txtMines;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Button button2;
		internal System.Windows.Forms.CheckBox chkBench;
		private System.Windows.Forms.TextBox txtBenchGoal;
		private MineFlagger.AIConfigControl aiConfigControl1;
		private MineFlagger.AIAnalysisControl aiAnalysisControl2;
		private System.Windows.Forms.Button button3;
		private System.Windows.Forms.TextBox textBox4;
        private System.Windows.Forms.Button button7;
		private System.Windows.Forms.CheckBox chkAutoScale;
		private System.Windows.Forms.TabControl tabControl1;
		private System.Windows.Forms.TabPage tabPage1;
		private System.Windows.Forms.TabPage tabPage2;
		private System.Windows.Forms.TabPage tabPage3;
		private System.Windows.Forms.Label lbeBench;
        private DigitsControl timeDigits;
        private DigitsControl minesLeftDigits;
        private SmileButton smileButton;
        private Button button1;
		private System.ComponentModel.IContainer components;

		#endregion

		public Form1() {

            rnd = new Random(~unchecked((int)DateTime.Now.Ticks));
            
			InitializeComponent();

            this.Text = AppName + " " + AppVersion;
            

            gameBoardView1.UserChangedBoard += new EventHandler(gameBoardControl1_UserChangedBoard);

            view = gameBoardView1;
            SetGameBoard(new GameBoard(5, 5, 4, rnd));

            smileButton.Click += new EventHandler(smileButton_Click);

            Load += new EventHandler(MainForm_Load);
        }

        public void SetGameBoard(GameBoard gameBoard)
        {
            GameBoard oldGameBoard = this.gameBoard;

            this.gameBoard = gameBoard;

            gameBoardView1.GameBoard = gameBoard;
            gameBoard.PropertyChanged += new PropertyChangedEventHandler(gameBoard_PropertyChanged);

            aiAnalysisControl2.SetUp(gameBoard, aiConfigControl1.AIConfig, view, rnd);

            if (oldGameBoard != null)
                oldGameBoard.Dispose();
        }

        void MainForm_Load(object sender, EventArgs e)
        {
            gameBoard.NewGame(int.Parse(txtWidth.Text), int.Parse(txtHeight.Text), int.Parse(txtMines.Text));
            aiAnalysisControl2.SetUp(gameBoard, aiConfigControl1.AIConfig, view, rnd);
        }


        void gameBoard_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (InvokeRequired)
                Invoke(new PropertyChangedEventHandler(gameBoard_PropertyChanged), sender, e);


            if (e.PropertyName == "PlayState")
            {
                if (gameBoard.PlayState == PlayState.Lost)
                    smileButton.SmileType = SmileType.Sad;
                else if (gameBoard.PlayState == PlayState.Won)
                    smileButton.SmileType = SmileType.Cool;
                else
                    smileButton.SmileType = SmileType.Happy;

            }
            else if (e.PropertyName == "MinesRemaining")
            {
                minesLeftDigits.Value = gameBoard.MinesRemaining;
            }
            else if (e.PropertyName == "Time")
            {
                timeDigits.Value = gameBoard.Time;
            }
        }





        // new game button
        private void smileButton_Click(object sender, EventArgs e)
        {
            gameBoard.NewGame(int.Parse(txtWidth.Text), int.Parse(txtHeight.Text), int.Parse(txtMines.Text));
            aiAnalysisControl2.SetUp(gameBoard, aiConfigControl1.AIConfig, view, rnd);

            gameBoardView1.Invalidate();
        }



        #region Data and Control odds and ends TODO: refactor



        // auto uncover
        private void button3_Click(object sender, System.EventArgs e)
        {
            MinesweeperAI mineAI = new MinesweeperAI(gameBoard, view, aiConfigControl1.AIConfig, rnd);
            bool result = mineAI.AutoUncover();
            
            view.InvalidateDirtyCells();

            userChangedBoard();
        }


        void gameBoardControl1_UserChangedBoard(object sender, EventArgs e)
        {
            userChangedBoard();
        }

        private void userChangedBoard()
        {            
            if (this.aiAnalysisControl2.AutoAnalyze)
            {
                aiAnalysisControl2.Analyze();
            }
        }

 



        #endregion

        private void chkBench_CheckedChanged(object sender, System.EventArgs e)
        {
            txtBenchGoal.Enabled = chkBench.Checked;
        }


        #region AI on Worker Thread

        Thread workerThread = null;

        MinesweeperAI curAI;
        private void button2_Click(object sender, System.EventArgs e)
        {
            if (workerThread != null && workerThread.IsAlive && !curAI.abort)
            {
                curAI.abort = true;
                button2.Enabled = false;

                while (workerThread.IsAlive)
                    Application.DoEvents();

                button2.Enabled = true;
                button2.Text = "Start AI";

            }
            else
            {
                curAI = null;

                workerThread = new Thread(new ThreadStart(this.DoWork_AI));

                button2.Text = "Abort";
                workerThread.Start();
            }
        }


        private delegate void UIBenchUpdate(string stats);
        void updatelbeBench(string stats)
        {
            if (InvokeRequired && !IsDisposed)
            {
                Invoke(new UIBenchUpdate(updatelbeBench), stats);
                return;
            }

            this.lbeBench.Text = stats;
        }

       

        void postDoWork_AI()
        {
            if (InvokeRequired && !IsDisposed)
            {
                Invoke(new UIWork(postDoWork_AI));
                return;
            }

            button2.Enabled = true;
            button2.Text = "Start AI";
        }

        public void DoWork_AI()
        {
            int wins = 0;
            int gamesToPlay = int.Parse(txtBenchGoal.Text);
            int games = 0;

            bool playUntilWin = !chkBench.Checked;

            for (games = 1; (playUntilWin || games <= gamesToPlay) && (curAI == null || !curAI.abort); games++)
            {

                gameBoard.NewGame(int.Parse(txtWidth.Text),
                    int.Parse(txtHeight.Text),
                    int.Parse(txtMines.Text));

                if (aiConfigControl1.AIConfig.ShowSteps)
                    view.InvalidateDirtyCells();

                MinesweeperAI ai = new MinesweeperAI(gameBoard, view, aiConfigControl1.AIConfig, rnd);
                curAI = ai;

                bool won = ai.PlayBoard();
                if (curAI.abort)
                {
                    break;
                }

                if (won)
                {
                    wins++;
                }
                else
                {
                    if (aiConfigControl1.AIConfig.ShowSteps)
                        view.InvalidateDirtyCells();
                }

                float percent = (float)Math.Round((decimal)(((float)wins / ((float)games) * 100f)), 2);
                int extrap20pc = (int)Math.Round((float)games * 0.2f, 0);

                int delta = wins - extrap20pc;

                string stats = "Games: " + games.ToString() + "     Wins: " + wins.ToString() + "  |  " + delta.ToString() + "     " + percent.ToString() + "%";
                updatelbeBench(stats);

                if (playUntilWin && won)
                    break;
            }

            games--;


            postDoWork_AI();

            view.InvalidateDirtyCells();



        }
        

  



        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (gameBoard != null)
            {
                gameBoard.Dispose();
                Application.DoEvents();
            }

            if (curAI != null && workerThread != null && workerThread.IsAlive)
            {
                curAI.abort = true;
                while (workerThread.IsAlive)
                    Application.DoEvents();
            }
        }




        #endregion


        #region AutoGen

        protected override void Dispose( bool disposing ) {
			if( disposing ) {
				if (components != null) {
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent() {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            this.txtWidth = new System.Windows.Forms.TextBox();
            this.txtHeight = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.txtMines = new System.Windows.Forms.TextBox();
            this.label3 = new System.Windows.Forms.Label();
            this.button2 = new System.Windows.Forms.Button();
            this.chkBench = new System.Windows.Forms.CheckBox();
            this.txtBenchGoal = new System.Windows.Forms.TextBox();
            this.button3 = new System.Windows.Forms.Button();
            this.textBox4 = new System.Windows.Forms.TextBox();
            this.button7 = new System.Windows.Forms.Button();
            this.chkAutoScale = new System.Windows.Forms.CheckBox();
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.tabPage1 = new System.Windows.Forms.TabPage();
            this.aiAnalysisControl2 = new MineFlagger.AIAnalysisControl();
            this.tabPage2 = new System.Windows.Forms.TabPage();
            this.aiConfigControl1 = new MineFlagger.AIConfigControl();
            this.tabPage3 = new System.Windows.Forms.TabPage();
            this.lbeBench = new System.Windows.Forms.Label();
            this.smileButton = new MineFlagger.SmileButton();
            this.minesLeftDigits = new MineFlagger.DigitsControl();
            this.timeDigits = new MineFlagger.DigitsControl();
            this.gameBoardView1 = new MineFlagger.GameBoardView();
            this.button1 = new System.Windows.Forms.Button();
            this.tabControl1.SuspendLayout();
            this.tabPage1.SuspendLayout();
            this.tabPage2.SuspendLayout();
            this.tabPage3.SuspendLayout();
            this.SuspendLayout();
            // 
            // txtWidth
            // 
            this.txtWidth.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.txtWidth.Location = new System.Drawing.Point(62, 44);
            this.txtWidth.Name = "txtWidth";
            this.txtWidth.Size = new System.Drawing.Size(32, 20);
            this.txtWidth.TabIndex = 1;
            this.txtWidth.Text = "30";
            // 
            // txtHeight
            // 
            this.txtHeight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.txtHeight.Location = new System.Drawing.Point(62, 20);
            this.txtHeight.Name = "txtHeight";
            this.txtHeight.Size = new System.Drawing.Size(32, 20);
            this.txtHeight.TabIndex = 2;
            this.txtHeight.Text = "16";
            // 
            // label1
            // 
            this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label1.Location = new System.Drawing.Point(14, 49);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(36, 23);
            this.label1.TabIndex = 3;
            this.label1.Text = "Width:";
            // 
            // label2
            // 
            this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label2.Location = new System.Drawing.Point(14, 25);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(40, 16);
            this.label2.TabIndex = 4;
            this.label2.Text = "Height:";
            // 
            // txtMines
            // 
            this.txtMines.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.txtMines.Location = new System.Drawing.Point(62, 68);
            this.txtMines.Name = "txtMines";
            this.txtMines.Size = new System.Drawing.Size(32, 20);
            this.txtMines.TabIndex = 5;
            this.txtMines.Text = "99";
            this.txtMines.TextChanged += new System.EventHandler(this.textBox3_TextChanged);
            // 
            // label3
            // 
            this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label3.Location = new System.Drawing.Point(14, 70);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(40, 23);
            this.label3.TabIndex = 6;
            this.label3.Text = "Mines:";
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(16, 200);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(96, 20);
            this.button2.TabIndex = 7;
            this.button2.Text = "Start AI";
            this.button2.Click += new System.EventHandler(this.button2_Click);
            // 
            // chkBench
            // 
            this.chkBench.Checked = true;
            this.chkBench.CheckState = System.Windows.Forms.CheckState.Checked;
            this.chkBench.Location = new System.Drawing.Point(126, 198);
            this.chkBench.Name = "chkBench";
            this.chkBench.Size = new System.Drawing.Size(64, 24);
            this.chkBench.TabIndex = 20;
            this.chkBench.Text = "Bench:";
            this.chkBench.CheckedChanged += new System.EventHandler(this.chkBench_CheckedChanged);
            // 
            // txtBenchGoal
            // 
            this.txtBenchGoal.Location = new System.Drawing.Point(183, 200);
            this.txtBenchGoal.Name = "txtBenchGoal";
            this.txtBenchGoal.Size = new System.Drawing.Size(41, 20);
            this.txtBenchGoal.TabIndex = 21;
            this.txtBenchGoal.Text = "10000";
            // 
            // button3
            // 
            this.button3.Location = new System.Drawing.Point(145, 204);
            this.button3.Name = "button3";
            this.button3.Size = new System.Drawing.Size(88, 20);
            this.button3.TabIndex = 27;
            this.button3.Text = "Auto Uncover";
            this.button3.Click += new System.EventHandler(this.button3_Click);
            // 
            // textBox4
            // 
            this.textBox4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.textBox4.Enabled = false;
            this.textBox4.Location = new System.Drawing.Point(16, 129);
            this.textBox4.Name = "textBox4";
            this.textBox4.Size = new System.Drawing.Size(32, 20);
            this.textBox4.TabIndex = 28;
            this.textBox4.Text = "1.0";
            // 
            // button7
            // 
            this.button7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.button7.Enabled = false;
            this.button7.Location = new System.Drawing.Point(53, 129);
            this.button7.Name = "button7";
            this.button7.Size = new System.Drawing.Size(64, 20);
            this.button7.TabIndex = 29;
            this.button7.Text = "Set Scale";
            // 
            // chkAutoScale
            // 
            this.chkAutoScale.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.chkAutoScale.Enabled = false;
            this.chkAutoScale.Location = new System.Drawing.Point(17, 101);
            this.chkAutoScale.Name = "chkAutoScale";
            this.chkAutoScale.Size = new System.Drawing.Size(76, 24);
            this.chkAutoScale.TabIndex = 34;
            this.chkAutoScale.Text = "AutoScale";
            // 
            // tabControl1
            // 
            this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.tabControl1.Controls.Add(this.tabPage1);
            this.tabControl1.Controls.Add(this.tabPage2);
            this.tabControl1.Controls.Add(this.tabPage3);
            this.tabControl1.Location = new System.Drawing.Point(502, 31);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(248, 256);
            this.tabControl1.TabIndex = 35;
            // 
            // tabPage1
            // 
            this.tabPage1.Controls.Add(this.button3);
            this.tabPage1.Controls.Add(this.aiAnalysisControl2);
            this.tabPage1.Location = new System.Drawing.Point(4, 22);
            this.tabPage1.Name = "tabPage1";
            this.tabPage1.Size = new System.Drawing.Size(240, 230);
            this.tabPage1.TabIndex = 0;
            this.tabPage1.Text = "Human Aides";
            // 
            // aiAnalysisControl2
            // 
            this.aiAnalysisControl2.AdvancedMines = -1;
            this.aiAnalysisControl2.AdvancedSafeCells = -1;
            this.aiAnalysisControl2.AutoAnalyze = false;
            this.aiAnalysisControl2.Location = new System.Drawing.Point(11, 11);
            this.aiAnalysisControl2.Name = "aiAnalysisControl2";
            this.aiAnalysisControl2.SimpleMines = -1;
            this.aiAnalysisControl2.SimpleSafeCells = -1;
            this.aiAnalysisControl2.Size = new System.Drawing.Size(220, 175);
            this.aiAnalysisControl2.TabIndex = 26;
            // 
            // tabPage2
            // 
            this.tabPage2.Controls.Add(this.txtBenchGoal);
            this.tabPage2.Controls.Add(this.chkBench);
            this.tabPage2.Controls.Add(this.button2);
            this.tabPage2.Controls.Add(this.aiConfigControl1);
            this.tabPage2.Location = new System.Drawing.Point(4, 22);
            this.tabPage2.Name = "tabPage2";
            this.tabPage2.Size = new System.Drawing.Size(240, 230);
            this.tabPage2.TabIndex = 1;
            this.tabPage2.Text = "AI Player";
            // 
            // aiConfigControl1
            // 
            this.aiConfigControl1.Location = new System.Drawing.Point(4, 4);
            this.aiConfigControl1.Name = "aiConfigControl1";
            this.aiConfigControl1.Size = new System.Drawing.Size(235, 188);
            this.aiConfigControl1.TabIndex = 25;
            // 
            // tabPage3
            // 
            this.tabPage3.Controls.Add(this.txtMines);
            this.tabPage3.Controls.Add(this.label1);
            this.tabPage3.Controls.Add(this.txtWidth);
            this.tabPage3.Controls.Add(this.label3);
            this.tabPage3.Controls.Add(this.label2);
            this.tabPage3.Controls.Add(this.txtHeight);
            this.tabPage3.Controls.Add(this.textBox4);
            this.tabPage3.Controls.Add(this.chkAutoScale);
            this.tabPage3.Controls.Add(this.button7);
            this.tabPage3.Location = new System.Drawing.Point(4, 22);
            this.tabPage3.Name = "tabPage3";
            this.tabPage3.Size = new System.Drawing.Size(240, 230);
            this.tabPage3.TabIndex = 2;
            this.tabPage3.Text = "Setup";
            // 
            // lbeBench
            // 
            this.lbeBench.Location = new System.Drawing.Point(502, 7);
            this.lbeBench.Name = "lbeBench";
            this.lbeBench.Size = new System.Drawing.Size(282, 16);
            this.lbeBench.TabIndex = 36;
            // 
            // smileButton
            // 
            this.smileButton.Location = new System.Drawing.Point(229, 4);
            this.smileButton.Name = "smileButton";
            this.smileButton.Size = new System.Drawing.Size(26, 26);
            this.smileButton.SmileType = MineFlagger.SmileType.Happy;
            this.smileButton.TabIndex = 40;
            this.smileButton.Text = "smileButton1";
            this.smileButton.Click += new System.EventHandler(this.smileButton_Click);
            // 
            // minesLeftDigits
            // 
            this.minesLeftDigits.Location = new System.Drawing.Point(14, 4);
            this.minesLeftDigits.MaxDigits = 5;
            this.minesLeftDigits.MinDigits = 3;
            this.minesLeftDigits.Name = "minesLeftDigits";
            this.minesLeftDigits.Size = new System.Drawing.Size(41, 25);
            this.minesLeftDigits.TabIndex = 39;
            this.minesLeftDigits.Text = "digitsControl1";
            this.minesLeftDigits.Value = 0;
            // 
            // timeDigits
            // 
            this.timeDigits.Location = new System.Drawing.Point(450, 4);
            this.timeDigits.MaxDigits = 5;
            this.timeDigits.MinDigits = 3;
            this.timeDigits.Name = "timeDigits";
            this.timeDigits.Size = new System.Drawing.Size(41, 25);
            this.timeDigits.TabIndex = 38;
            this.timeDigits.Text = "digitsControl1";
            this.timeDigits.Value = 0;
            // 
            // gameBoardView1
            // 
            this.gameBoardView1.BackColor = System.Drawing.SystemColors.Control;
            this.gameBoardView1.GameBoard = null;
            this.gameBoardView1.Location = new System.Drawing.Point(9, 34);
            this.gameBoardView1.Name = "gameBoardView1";
            this.gameBoardView1.Size = new System.Drawing.Size(358, 217);
            this.gameBoardView1.TabIndex = 37;
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(721, 6);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(25, 23);
            this.button1.TabIndex = 41;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.BackColor = System.Drawing.SystemColors.Control;
            this.ClientSize = new System.Drawing.Size(755, 301);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.smileButton);
            this.Controls.Add(this.minesLeftDigits);
            this.Controls.Add(this.timeDigits);
            this.Controls.Add(this.gameBoardView1);
            this.Controls.Add(this.lbeBench);
            this.Controls.Add(this.tabControl1);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Name = "Form1";
            this.Text = "MineFlagger v0.x";
            this.tabControl1.ResumeLayout(false);
            this.tabPage1.ResumeLayout(false);
            this.tabPage2.ResumeLayout(false);
            this.tabPage2.PerformLayout();
            this.tabPage3.ResumeLayout(false);
            this.tabPage3.PerformLayout();
            this.ResumeLayout(false);

		}
		#endregion

		[STAThread]
		static void Main() {
			Application.Run(new Form1());
        }

        #endregion

        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            // -- temp: for testing minesLeftDigits

            int val;
            if (int.TryParse(txtMines.Text, out val))
                minesLeftDigits.Value = val;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MainForm mainForm = new MainForm();
            mainForm.SetGameBoard(gameBoard);
            
            mainForm.Show();
        }





    }


    public delegate void UIWork();




}
